1
2
3
4
5 package com.jguild.jrpm.io;
6
7 import java.io.DataInputStream;
8 import java.io.IOException;
9 import java.util.Comparator;
10 import java.util.HashMap;
11 import java.util.TreeSet;
12
13 import org.apache.log4j.Logger;
14
15 import com.jguild.jrpm.io.datatype.DataTypeIf;
16 import com.jguild.jrpm.io.datatype.TypeFactory;
17
18
19 /***
20 * This class represents the abstract definition of a header structur.
21 * It can be either a signature or a header. The tags of such a structure
22 * can be accessed by either their tag id or by their tag name.
23 * Also all available and all read tag names in this structure can be accessed.
24 *
25 * @author kuss
26 * @version $Id: Header.java,v 1.10 2004/09/09 09:52:33 pnasrat Exp $
27 **/
28 public abstract class Header {
29 private static final int HEADER_LENGTH = 16;
30 private static final Logger logger = Logger.getLogger(Header.class);
31 private HashMap store = new HashMap();
32 private IndexEntry[] indexes;
33 private int version;
34 private long indexDataSize;
35 private long indexNumber;
36 private boolean rawHeader = false;
37 /*** The size in bytes of this structure */
38 protected long size;
39
40 /***
41 *
42 * Create a header structure from an input stream.
43 *
44 * The header structure of a signature or a header can be read and
45 * also the index entries containing the tags for this rpm section
46 * (signature or header).
47 *
48 * Unless we have a raw header from headerUnload or the database,
49 * a header is read consisting of the following fields:
50 * <code><pre>
51 * byte magic[3]; (3 byte) (8e ad e8)
52 * int version; (1 byte)
53 * byte reserved[4]; (4 byte)
54 * long num_index; (4 byte)
55 * long num_data; (4 byte)
56 * </pre></code>
57 *
58 * Afterwards the index entries are read and then the tags and the
59 * correspondig data entries are read.
60 *
61 * @param inputStream An inputstream containing rpm file informations
62 * @param rawHeader Are we a raw header (from headerUnload or rpmdb)
63 * @throws IOException if an error occurs on reading informations
64 * out of the stream
65 */
66 public Header(DataInputStream inputStream, boolean rawHeader) throws IOException {
67 if (logger.isDebugEnabled()) {
68 logger.debug("Start Reading Header");
69 }
70
71 if (!rawHeader) {
72
73 size = HEADER_LENGTH;
74
75 check(inputStream.readUnsignedByte() == 0x8E);
76 check(inputStream.readUnsignedByte() == 0xAD);
77 check(inputStream.readUnsignedByte() == 0xE8);
78 version = inputStream.readUnsignedByte();
79
80 if (logger.isDebugEnabled()) {
81 logger.debug("version: " + version);
82 }
83
84
85 inputStream.skipBytes(4);
86 }
87
88 indexNumber = inputStream.readInt();
89
90 if (logger.isDebugEnabled()) {
91 logger.debug("indexes available: " + indexNumber);
92 }
93
94 indexDataSize = inputStream.readInt();
95
96 if (logger.isDebugEnabled()) {
97 logger.debug("index data size: " + indexDataSize);
98 }
99
100
101
102
103
104 TreeSet _indexes = new TreeSet(new Comparator() {
105 public int compare(Object o1, Object o2) {
106 return (int) (((IndexEntry) o1).getOffset() - ((IndexEntry) o2).getOffset());
107 }
108
109 public boolean equals(Object o) {
110 return false;
111 }
112 });
113
114 for (int i = 0; i < indexNumber; i++) {
115 IndexEntry index = new IndexEntry(inputStream);
116
117 _indexes.add(index);
118 size += index.getSize();
119 }
120
121 indexes = new IndexEntry[0];
122 indexes = (IndexEntry[]) _indexes.toArray(indexes);
123
124
125 for (int i = 0; i < indexes.length; i++) {
126 IndexEntry index = indexes[i];
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 DataTypeIf dataObject = null;
145
146 if (logger.isDebugEnabled()) {
147 logger.debug("Reading for tag '" + getTagNameForId(index.getTag()) + "' '" + index.getCount() + "' entries of type '" +
148 index.getType().getName() + "'");
149 }
150
151 dataObject = TypeFactory.createFromStream(inputStream, index,
152 (i < (indexes.length - 1)) ? (indexes[i + 1].getOffset() - index.getOffset()) : (indexDataSize - index.getOffset()));
153
154
155 size += dataObject.getSize();
156
157 store.put(new Long(index.getTag()), dataObject);
158 }
159
160 if (logger.isDebugEnabled()) {
161 logger.debug("");
162 }
163
164 if (logger.isDebugEnabled()) {
165 logger.debug("Finished Reading Header");
166 }
167 }
168
169 /***
170 * Construct a header structure for the given input stream.
171 * @param inputStream
172 * @throws IOException
173 */
174 public Header(DataInputStream inputStream) throws IOException {
175 this(inputStream, false);
176 }
177
178 /***
179 * Read all known tag names for this header structure.
180 *
181 * @return An array of tag names
182 */
183 public static String[] getKnownTagNames() {
184 return new String[0];
185 }
186
187 /***
188 * Get the size in bytes of this structure
189 *
190 * @return The size in bytes.
191 */
192 public long getSize() {
193 return size;
194 }
195
196 /***
197 * Get a tag by id as a Long
198 *
199 * @param tag A tag id as a Long
200 * @return A data struct containing the data of this tag
201 */
202 public DataTypeIf getTag(Long tag) {
203 return (DataTypeIf) store.get(tag);
204 }
205
206 /***
207 * Get a tag by id as a long
208 *
209 * @param tag A tag id as a long
210 * @return A data struct containing the data of this tag
211 */
212 public DataTypeIf getTag(long tag) {
213 return getTag(new Long(tag));
214 }
215
216 /***
217 * Get a tag by name
218 *
219 * @param tagname A tag name
220 * @return A data struct containing the data of this tag
221 */
222 public DataTypeIf getTag(String tagname) {
223 return getTag(getTagIdForName(tagname));
224 }
225
226 /***
227 * Set a tag by id as a Long
228 *
229 * @param tag A tag id as a Long
230 * @param data A data struct containing the data of this tag
231 */
232 public void setTag(Long tag, DataTypeIf data) {
233 isValidTag(tag.longValue());
234 store.put(tag, data);
235 }
236
237 /***
238 * Set a tag by id as a long
239 *
240 * @param tag A tag id as a long
241 * @param data A data struct containing the data of this tag
242 */
243 public void setTag(long tag, DataTypeIf data) {
244 setTag(new Long(tag), data);
245 }
246
247 /***
248 * Set a tag by id as a string
249 *
250 * @param tagname A tag id as a string
251 * @param data A data struct containing the data of this tag
252 */
253 public void setTag(String tagname, DataTypeIf data) {
254 setTag(getTagIdForName(tagname), data);
255 }
256
257 /***
258 * Get all tag ids contained in this rpm file.
259 *
260 * @return All tag ids contained in this rpm file.
261 */
262 public long[] getTagIds() {
263 Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
264 long[] ret = new long[tmp.length];
265
266 for (int i = 0; i < tmp.length; i++) {
267 ret[i] = tmp[i].longValue();
268 }
269
270 return ret;
271 }
272
273 /***
274 * Get all tag names contained in this rpm file.
275 *
276 * @return All tag names contained in this rpm file.
277 */
278 public String[] getTagNames() {
279 Long[] tmp = (Long[]) store.keySet().toArray(new Long[0]);
280 String[] ret = new String[tmp.length];
281
282 for (int i = 0; i < tmp.length; i++) {
283 ret[i] = getTagNameForId(tmp[i].longValue());
284 }
285
286 return ret;
287 }
288
289 /***
290 * Asserts a boolean value and throws an exception if it
291 * is false
292 * @param test A boolean test variable
293 * @throws IOException if the variable test is false
294 */
295 private static final void check(boolean test)
296 throws IOException {
297 if (!test) {
298 throw new IOException("Corrupted archive");
299 }
300 }
301
302 /***
303 * Read a tag with a given tag name. The tag will be read out of the
304 * class defined in getTagEnum().
305 *
306 * @param tagname A RPM tag name
307 * @return The id of the RPM tag
308 * @throws IllegalArgumentException if the tag name was not found
309 */
310 public abstract long getTagIdForName(String tagname);
311
312 /***
313 * Read a tag with a given tag id. The tag will be read out of the
314 * class defined in getTagEnum().
315 *
316 * @param tagid A RPM tag id
317 * @return The name of the RPM tag
318 * @throws IllegalArgumentException if the tag id was not found
319 */
320 public abstract String getTagNameForId(long tagid);
321
322 /***
323 * Test if the given tagid is associated with a valid tag
324 *
325 * @param tagid The id of a tag
326 * @return TRUE if the tagid is valid
327 */
328 public abstract boolean isValidTag(long tagid);
329
330 /***
331 * Test if the given tagname is associated with a valid tag
332 *
333 * @param tagname The name of a tag
334 * @return TRUE if the tagname is valid
335 */
336 public abstract boolean isValidTag(String tagname);
337 }